package com.example.flowable.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.annotations.*;
import com.example.flowable.FLowableUtils;
import com.example.flowable.model.TaskModel;
import com.example.flowable.service.FlowableService;
import com.example.utils.PathUtils;
import com.example.utils.Results;
import com.example.utils.imagecode.GetMessage;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import liquibase.pro.packaged.S;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceBuilder;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import sun.misc.IOUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;

/**
 * @Classname FlowableController
 * @Description TODO
 * @Date 2022/8/14 17:43
 * @Created by XiongXiong
 * @Author: X.I.O
 */
@Auth
@RestController("/flowable")
public class FlowableDemoController {

    @Autowired
    FLowableUtils fLowableUtils;

    @Autowired
    FlowableService flowableService;

    @GetMapping(value = "/getprocessallnode",desc = "获取流程所有节点")
    public JSONObject getProcessAllNodeController(@Param("processId")String processId){
        Map<String,Object> map = new HashMap<>();
        List<FlowElement> list=flowableService.getAllNodesByProcessId(processId,map);
        JSONArray jsonArray = new JSONArray();
        JSONObject obj = null;
        for (FlowElement ele : list) {
            obj=new JSONObject();
            obj.put("id",ele.getId());
            obj.put("name",ele.getName());
            jsonArray.add(obj);
        }
        return Results.success(jsonArray);
    }

    @GetMapping("/gethistory")
    public JSONObject getHistory(@Param("processId")String processId){
        HistoryService historyService=fLowableUtils.getHistoryService();
        // 获得活动的节点
        List<HistoricActivityInstance> highLightedActivityList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).
                orderByHistoricActivityInstanceStartTime().asc().list();
        List<Map<String,String>> maps=new ArrayList<>();
        boolean flag=false;
        for (HistoricActivityInstance tempActivity : highLightedActivityList) {
            Map<String,String> map=new HashMap<>();
            String activityId = tempActivity.getActivityId();

            String name=tempActivity.getActivityName();
            String czr=tempActivity.getAssignee();
            String type=tempActivity.getActivityType();
            if("userTask".equals(type)){
                map.put("name",name);
                map.put("czr",czr);
            }
            if("exclusiveGateway".equals(type)){
                Map<String,String> nextMap=getLastMap(maps);
                nextMap.put("event",name);
                flag=true;
            }
            if("sequenceFlow".equals(type)){
                if(flag){
                    Map<String,String> nextMap=getLastMap(maps);
                    nextMap.put("eventResult",name);
                    flag=false;
                }
            }
            if("endEvent".equals(type)){
                map.put("end","isend");
            }
            if(!map.isEmpty()){
                maps.add(map);
            }
        }
        return Results.success(maps);
    }

    private Map<String,String> getLastMap( List<Map<String,String>> maps){
        if(maps == null || maps.isEmpty()){
            return new HashMap<>();
        }
        return maps.get(maps.size() - 1);
    }

    @GetMapping(value = "/nodechange",desc = "节点改变")
    public JSONObject nodeChangeController(@Param("processId")String processId,
                                           @Param("currentId")String currentId,
                                           @Param("nodeId")String nodeId){
        flowableService.changeProcessInstancsNode(processId,currentId,nodeId);
        return Results.success("修改成功");
    }

    @GetMapping(value = "/getprocessinfo",desc = "获取流程信息")
    public JSONObject getProcessInfoController(@Param("processId")String processId){
        ProcessInstance processInstance=flowableService.getProcessInstanceById(processId);
        JSONObject object=new JSONObject();
        object.put("id",processInstance.getId());
        object.put("name",processInstance.getName());
        List<Task> taskList=flowableService.getTaskListByProcessInstanceId(processInstance.getId());
        for (int i = 0; i < taskList.size(); i++) {
            Task task = taskList.get(i);
            System.out.println(task.getId());
            System.out.println(task.getName());
            System.out.println(task.getAssignee());
        }
        return object;
    }




    @GetMapping(value = "/submittask",desc = "提交任务")
    public JSONObject submitTaskController(@Param(value = "taskid",desc = "任务id")String taskId,
                                           @Param(value = "msg",desc = "任务信息")String msg){
        flowableService.submitTask(taskId,"105",msg);
        return Results.success("任务提交成功");
    }

    @GetMapping(value = "/getallprocess",desc = "获取流程所有节点")
    public JSONObject getProcessList(@Param(value = "deploymentId",desc = "部署的流程id") String deploymentId){
        List<Process> processors= flowableService.getProcessListByDeployId(deploymentId);
        JSONArray array = new JSONArray();
        for (int i = 0; i < processors.size() ; i++) {
            Process process = processors.get(i);
            JSONObject object=new JSONObject();
            object.put("id",process.getId());
            object.put("name",process.getName());
            array.add(object);
        }
        return Results.success(array);
    }

    @GetMapping(value = "/deployprocess",desc = "流程部署")
    public JSONObject deploymentProcess() throws FileNotFoundException {
        String path= PathUtils.getPath()+ File.separator+"start-ui"+File.separator + "processes";
        File file=new File(path);
        File[] files=file.listFiles();
        for (int i = 0; i < files.length ; i++) {
            File f = files[i];
           Deployment deployment=flowableService.deploymentByFile(f.getPath());
            System.out.println(deployment.getId()+" 流程id");
            System.out.println(f.getName());
        }
        return Results.success(path);
    }

    @GetMapping(value = "/getProcessDefKey",desc = "通过部署的流程id获取流程")
    public JSONObject getProcessDefKeyController(@Param(value = "deployId",desc = "部署的流程id")String deployId){
        ProcessDefinition processDefinition=flowableService.getProcessDefinitionByDeployId(deployId);
        System.out.println(processDefinition.getId());
        System.out.println(processDefinition.getKey());
        return Results.success(processDefinition.getKey());
    }

    @GetMapping(value = "/createProcess",desc = "创建流程")
    public JSONObject createProcesController(@Param(value = "deployId",desc = "部署的流程id")String deployId,
                                             @Param(value = "title",desc = "流程标题")String title){
        Map<String, Object> params = new HashMap<>();
        params.put("uid",1);
        ProcessInstance processInstance=flowableService.createProcessInstance(deployId,title,"1",params);
        System.out.println(processInstance.getId());
        return Results.success(processInstance.getName());
    }

    @Auth
    @GetMapping(value = "/deploy",desc = "部署流程")
    public JSONObject deployFlowable(){
        RepositoryService service=fLowableUtils.getRepositoryService();
        service.createDeployment().name("请假")
                .addClasspathResource("process/ask_for_leave.bpmn20.xml")
        .deploy();
        return Results.success("部署成功");
    }


    @GetMapping(value = "/deploylist",desc = "部署的流程列表")
    public JSONObject getDeploymentList(){
        RepositoryService service=fLowableUtils.getRepositoryService();
        List<ProcessDefinition> list = service.createProcessDefinitionQuery().list();
        List<Map<String,Object>> mapList=new ArrayList<>();
        for (ProcessDefinition processDefinition : list) {
            Map<String, Object> map=new HashMap<>();
            map.put("id",processDefinition.getId());
            map.put("name",processDefinition.getName());
            mapList.add(map);
            System.out.println("processDefinition id ==> "+ processDefinition.getId());
            System.out.println("processDefinition ==> "+processDefinition.getId()+" , "+processDefinition.getName()+"  key:"+ processDefinition.getKey());
        }
        return Results.success(mapList);
    }

    @GetMapping(value = "createtask",desc = "创建任务")
    public JSONObject creteTaskController(){
        String staffId = "";
        HashMap<String, Object> map = new HashMap<>();
        map.put("uid", staffId);
        RuntimeService runtimeService=fLowableUtils.getRuntimeService();
        ProcessInstanceBuilder processInstanceBuilder=runtimeService.createProcessInstanceBuilder();
        processInstanceBuilder.businessKey("123456789");
        processInstanceBuilder.processDefinitionKey("ask_for_leave");
        processInstanceBuilder.name("我要请假了");
        processInstanceBuilder.variables(map);
        ProcessInstance processInstance=processInstanceBuilder.start();
        //  ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("ask_for_leave", map);
        Authentication.setAuthenticatedUserId(null);
        runtimeService.setVariable(processInstance.getId(), "name", "javaboy");
        runtimeService.setVariable(processInstance.getId(), "reason", "休息一下");
        runtimeService.setVariable(processInstance.getId(), "days", 10);
        return Results.success("创建成功"+processInstance.getId());
    }

    @GetMapping(value = "/getuserdeal",desc = "获取用户的已办")
    public JSONObject getUserDealController(@Param("uid")String uid,
                                            @Param(value = "pageNum",defalultValue = "1")Integer pageNum,
                                            @Param(value = "pageSize",defalultValue = "10")Integer pageSize){
        HistoryService historyService=fLowableUtils.getHistoryService();
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                //按结束时间正向排序
                .orderByHistoricTaskInstanceEndTime().asc()
                .taskAssignee(uid).listPage(pageNum,pageSize);
        RuntimeService runtimeService=fLowableUtils.getRuntimeService();
        List<TaskModel> taskModelList=new ArrayList<>();
        for (HistoricTaskInstance historicTaskInstance : list) {
            String processInstanceId=historicTaskInstance.getProcessInstanceId();
            ProcessInstance processInstance=runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            System.out.println(processInstance.getName());
            if(processInstance!=null){
                TaskModel taskModel=new TaskModel();
                taskModel.setTaskId(historicTaskInstance.getId());
                taskModel.setTaskName(historicTaskInstance.getName());
                taskModel.setTitle(processInstance.getName());
                taskModel.setProcessId(processInstance.getId());
                taskModel.setBindID(processInstance.getBusinessKey());
                taskModel.setFromUID(historicTaskInstance.getOwner());
                taskModel.setToUID(historicTaskInstance.getAssignee());
                taskModelList.add(taskModel);
            }else {
                HistoricProcessInstance historicProcessInstance=historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
                TaskModel taskModel=new TaskModel();
                taskModel.setTaskId(historicTaskInstance.getId());
                taskModel.setTaskName(historicTaskInstance.getName());
                taskModel.setTitle(historicProcessInstance.getName());
                taskModel.setProcessId(historicProcessInstance.getId());
                taskModel.setBindID(historicProcessInstance.getBusinessKey());
                taskModel.setFromUID(historicTaskInstance.getOwner());
                taskModel.setToUID(historicTaskInstance.getAssignee());
                taskModelList.add(taskModel);
            }
        }
        return Results.success(taskModelList);
    }

    @GetMapping(value = "/getuserdb",desc = "获取用户的待办")
    public JSONObject getUserDbController(@Param("uid")String uid){
        TaskService taskService=fLowableUtils.getTaskService();

        RuntimeService runtimeService=fLowableUtils.getRuntimeService();
        List<Task> tasks = taskService.createTaskQuery()
                .taskCandidateOrAssigned(uid)
                .list();
        List<Map<String, Object>> list = new ArrayList<>();
        if (!tasks.isEmpty()) {

            for (Task task : tasks) {
                Map<String, Object> map = new HashMap<>();
                //代办id
                String taskId = task.getId();
                //流程id
                String processId=task.getProcessInstanceId();

                ProcessInstance processInstance=runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
                //代办节点名称
                String taskName = task.getName();
                //创建时间
                Date createTime = task.getCreateTime();
                //当前处理人
                String userid=task.getAssignee();
                //
                String ownerId=task.getOwner();
                map.put("taskId", taskId);
                map.put("taskName", taskName);
                map.put("processId",processId);
                map.put("title",processInstance.getName());
                map.put("owenId",ownerId);
                map.put("userid",userid);
                map.put("createTime", createTime);
                list.add(map);
            }
        }
        return Results.success(list);
    }

    @GetMapping(value = "/submittozuzhang",desc = "提交给组长")
    public JSONObject submitToZuZhangController(){
        String zuzhangId = "90";
        String staffId = "1000";
        TaskService taskService=fLowableUtils.getTaskService();
        RuntimeService runtimeService=fLowableUtils.getRuntimeService();
        //员工查找到自己的任务，然后提交给组长审批
        List<Task> list = taskService.createTaskQuery().taskAssignee(staffId).orderByTaskId().desc().list();

        for (Task task : list) {
            Map<String,Object> objectMap=runtimeService.getVariables(task.getProcessInstanceId());
            System.out.println(JSONObject.toJSONString(objectMap));
            Map<String, Object> map = new HashMap<>();
            //提交给组长的时候，需要指定组长的 id
            map.put("uid", zuzhangId);
            Authentication.setAuthenticatedUserId(zuzhangId);
            taskService.addComment(task.getId(),task.getProcessInstanceId(),"这是审批信息");

            taskService.complete(task.getId(), map);

            Authentication.setAuthenticatedUserId(null);
        }
        return Results.success("提交成功");
    }

    @GetMapping(value = "/zuzhangtomananger",desc = "组长提交给经理")
    public JSONObject zuZhangToMananger(){
        String zuzhangId = "90";
        String managerId="80";
        TaskService taskService=fLowableUtils.getTaskService();
        List<Task> list = taskService.createTaskQuery().taskAssignee(zuzhangId).orderByTaskId().desc().list();
        for (Task task : list) {
            Map<String, Object> map = new HashMap<>();
            //组长审批的时候，如果是同意，需要指定经理的 id
            map.put("uid", managerId);
            map.put("checkResult", "通过");
            //System.out.println(JSONObject.toJSONString(task.getCaseVariables()));
            taskService.complete(task.getId(), map);
        }
        return Results.success("组长审核通过");
    }

    @GetMapping(value = "/managersucess",desc = "经理审核通过")
    public JSONObject managerSucessController(){
        String managerId="80";
        TaskService taskService=fLowableUtils.getTaskService();
        List<Task> list = taskService.createTaskQuery().taskAssignee(managerId).orderByTaskId().desc().list();
        for (Task task : list) {
            Map<String, Object> map = new HashMap<>();
            map.put("checkResult", "通过");
            taskService.complete(task.getId(), map);
        }
        return Results.success("经理审核通过");
    }

    @GetMapping(value = "/getnextnodeinfo",desc = "获取流程下一节点信息")
    public JSONObject getNextNodeInfoController(@Param("processId")String processId){
        List<Task> tasks=flowableService.getTaskListByProcessInstanceId(processId);
        if(tasks==null){
            return Results.error("任务信息为null");
        }
        RuntimeService runtimeService=fLowableUtils.getRuntimeService();
        Task task=tasks.get(0);
        ExecutionEntity ee = (ExecutionEntity) runtimeService.createExecutionQuery()
                .executionId(task.getExecutionId()).singleResult();
        // 当前审批节点
        String crruentActivityId = ee.getActivityId();

        RepositoryService repositoryService=fLowableUtils.getRepositoryService();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(crruentActivityId);
        // 输出连线
        List<SequenceFlow> outFlows = flowNode.getOutgoingFlows();
        JSONArray array=new JSONArray();
        for (SequenceFlow seq : outFlows) {
            //当前审批节点
            FlowElement sourceFlowElement = seq.getSourceFlowElement();
            JSONObject obj=new JSONObject();
            obj.put("now","当前节点："+sourceFlowElement.getId() +" 节点名称： "+sourceFlowElement.getName());
            // 下一个审批节点
            FlowElement targetFlow = seq.getTargetFlowElement();
            if (targetFlow instanceof UserTask) {
                obj.put("next","下一节点："+targetFlow.getId() +" 节点名称： "+targetFlow.getName());
            }
            // 如果下个审批节点为结束节点
            if (targetFlow instanceof EndEvent) {
                obj.put("end","下一节点："+targetFlow.getId() +" 节点名称： "+targetFlow.getName());
            }
            //如果下个节点是网关
            if(targetFlow instanceof ExclusiveGateway){
                flowableService.dealGetWay(targetFlow,new HashMap());
                obj.put("getway","下一节点: "+targetFlow.getId() + "节点名称: "+targetFlow.getName()+" ");
            }
            array.add(obj);
        }
        return Results.success(array);
    }



    @GetMapping(value = "/pic",desc = "获取流程图")
    public void getFLowablePic(HttpServerResponse response, @Param("processId") String processId) throws IOException {
        RuntimeService runtimeService=fLowableUtils.getRuntimeService();
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        if (pi == null) {
            return;
        }
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(processId)
                .list();

        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }

        RepositoryService repositoryService=fLowableUtils.getRepositoryService();

        /**
         * 生成流程图
         */
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engineConfiguration = fLowableUtils.getProcessEngine().getProcessEngineConfiguration();;
        engineConfiguration.setActivityFontName("宋体");
        engineConfiguration.setLabelFontName("宋体");
        engineConfiguration.setAnnotationFontName("宋体");
        ProcessDiagramGenerator diagramGenerator = engineConfiguration.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engineConfiguration.getActivityFontName(),
                engineConfiguration.getLabelFontName(),
                engineConfiguration.getAnnotationFontName(),
                engineConfiguration.getClassLoader(), 1.0, false);

        response.putHeader("Pragma", "No-cache");
        response.putHeader("Cache-Control", "no-cache");
        response.putHeader("Expires", "0");
        response.putHeader("content-type", "image/jpeg");
        try {

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte buff[] = new byte[1024];
            int len = 0;
            while ((len = in.read(buff)) != -1) {
                baos.write(buff, 0, len);
            }
            baos.flush();
            Buffer buffer = Buffer.buffer();
            buffer.appendBytes(baos.toByteArray());
            response.end(buffer);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
